﻿using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using System.Security.Cryptography;

namespace SenGe.Domain.Utils
{
    /// <summary>
    /// 安全密码哈希工具
    /// </summary>
    public class SecurePasswordHasher
    {
        // 推荐参数配置
        private const int SaltSize = 16; // 128位盐值
        private const int Iterations = 150_666; // 迭代次数
        private const int OutputLength = 32; // 256位输出

        /// <summary>
        /// 生成安全的密码哈希
        /// </summary>
        public static string HashPassword(string password)
        {
            // 生成随机盐值
            byte[] salt = new byte[SaltSize];
            using (var rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(salt);
            }

            // 使用PBKDF2-SM3生成密钥
            byte[] hash = Pbkdf2Sm3(password, salt, Iterations, OutputLength);

            // 返回格式: 算法$迭代次数$盐$哈希
            return $"sm3-pbkdf2${Iterations}${Convert.ToBase64String(salt)}${Convert.ToBase64String(hash)}";
        }

        /// <summary>
        /// 验证密码
        /// </summary>
        public static bool VerifyPassword(string hashedPassword, string inputPassword)
        {
            // 解析存储的哈希值
            var parts = hashedPassword.Split('$');
            if (parts.Length != 4 || parts[0] != "sm3-pbkdf2")
                throw new FormatException("无效的密码格式");

            int iterations = int.Parse(parts[1]);
            byte[] salt = Convert.FromBase64String(parts[2]);
            byte[] storedHash = Convert.FromBase64String(parts[3]);

            // 重新计算输入密码的哈希
            byte[] computedHash = Pbkdf2Sm3(inputPassword, salt, iterations, storedHash.Length);

            // 安全比较（防时序攻击）
            return SlowEquals(storedHash, computedHash);
        }

        /// <summary>
        /// 基于SM3的PBKDF2实现
        /// </summary>
        private static byte[] Pbkdf2Sm3(string password, byte[] salt, int iterations, int outputLength)
        {
            byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(password);

            var generator = new Pkcs5S2ParametersGenerator(new SM3Digest());
            generator.Init(passwordBytes, salt, iterations);

            KeyParameter keyParam = (KeyParameter)generator.GenerateDerivedMacParameters(outputLength * 8);
            return keyParam.GetKey();
        }

        /// <summary>
        /// 安全比较（防时序攻击）
        /// </summary>
        private static bool SlowEquals(byte[] a, byte[] b)
        {
            uint diff = (uint)a.Length ^ (uint)b.Length;
            for (int i = 0; i < a.Length && i < b.Length; i++)
            {
                diff |= (uint)(a[i] ^ b[i]);
            }
            return diff == 0;
        }

    }
}
